package com.ec.system.modules.sys.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ec.common.constant.CommonConstant;
import com.ec.core.common.constants.TenantConstant;
import com.ec.core.common.core.base.BasePageVO;
import com.ec.core.common.enums.RandomTypeEnum;
import com.ec.core.common.exception.BizException;
import com.ec.core.common.utils.*;
import com.ec.core.mybatis.utils.CorePageUtil;
import com.ec.core.secure.utils.SecureUtil;
import com.ec.system.common.enums.RespResultEnum;
import com.ec.system.modules.sys.dto.QueryTenantDTO;
import com.ec.system.modules.sys.dto.SysTenantDTO;
import com.ec.system.modules.sys.entity.*;
import com.ec.system.modules.sys.mapper.SysTenantMapper;
import com.ec.system.modules.sys.service.*;
import com.ec.system.modules.sys.vo.InitTenantAccountVO;
import com.ec.system.modules.sys.vo.SysTenantVO;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @description:
 * @author: Eric Lee
 * @time: 2021/9/22 11:28
 */
@Service
public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant> implements ISysTenantService {
    @Resource
    private ISysDeptService sysDeptService;
    @Resource
    private ISysRoleService sysRoleService;
    @Resource
    private ISysRoleUserService sysRoleUserService;
    @Resource
    private ISysUserService sysUserService;
    @Resource
    private ISysRoleMenuService sysRoleMenuService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public InitTenantAccountVO addTenant(SysTenantDTO tenantDTO) {
        // 校验前缀是否存在
        tenantDTO.setAccountPrefix(tenantDTO.getAccountPrefix().toUpperCase());
        tenantDTO.setTenantCode(tenantDTO.getTenantCode().toUpperCase());
        long count = baseMapper.selectCount(Wrappers.<SysTenant>lambdaQuery().eq(SysTenant::getAccountPrefix, tenantDTO.getAccountPrefix()));
        if (count > 0) {
            throw new BizException(RespResultEnum.ACCOUNT_PREFIX_EXISTS_ERROR);
        }
        SysTenant SysTenant = new SysTenant();
        BeanUtilEx.copyProperties(tenantDTO, SysTenant);
        // 添加租户信息
        this.save(SysTenant);
        SysDept sysDeptEntity = new SysDept();
        sysDeptEntity.setTenantId(SysTenant.getTenantId());
        sysDeptEntity.setDeptName(tenantDTO.getTenantName() + "总部");
        sysDeptEntity.setParentId(0L);
        // 添加部门信息
        sysDeptService.save(sysDeptEntity);
        // 添加角色信息
        SysRole SysRole = new SysRole();
        SysRole.setTenantId(SysTenant.getTenantId());
        SysRole.setRoleName(CommonConstant.TENANT_ADMINISTRATOR_ROLE_NAME);
        SysRole.setRoleCode(CommonConstant.TENANT_ADMINISTRATOR_ROLE_CODE);
        SysRole.setRoleDesc(CommonConstant.TENANT_ADMINISTRATOR_ROLE_DESC);
        SysRole.setRoleSort(10000);
        sysRoleService.save(SysRole);
        // 初始化一个租户管理员账号
        return initAccount(SysTenant, sysDeptEntity.getDeptId(), SysRole.getRoleId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateTenant(SysTenantDTO tenantDTO) {
        SysTenant SysTenant = new SysTenant();
        BeanUtilEx.copyProperties(tenantDTO, SysTenant, "accountPrefix", "tenantCode", "tenantStatus");
        return this.updateById(SysTenant);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteTenant(SysTenantDTO tenantDTO) {
        LambdaUpdateWrapper<SysTenant> updateWrapper = Wrappers.<SysTenant>lambdaUpdate()
                .eq(SysTenant::getTenantId, tenantDTO.getTenantId())
                .notIn(SysTenant::getTenantCode, TenantConstant.EC_HEADQUARTERS);
        return this.remove(updateWrapper);
    }

    @Override
    public BasePageVO<SysTenantVO> listTenant(QueryTenantDTO listTenantDTO) {
        LambdaQueryWrapper<SysTenant> wrapper = Wrappers.lambdaQuery();
        if (StringUtilsEx.isNotBlank(listTenantDTO.getTenantName())) {
            wrapper.like(SysTenant::getTenantName, listTenantDTO.getTenantName());
        }
        if (null != listTenantDTO.getTenantStatus()) {
            wrapper.eq(SysTenant::getTenantStatus, listTenantDTO.getTenantStatus());
        }
        if (null != listTenantDTO.getLeaseTimeStart()) {
            wrapper.ge(SysTenant::getLeaseTimeStart, listTenantDTO.getTenantStatus());
        }
        if (null != listTenantDTO.getLeaseTimeEnd()) {
            wrapper.lt(SysTenant::getLeaseTimeEnd, listTenantDTO.getLeaseTimeEnd());
        }
        if (StringUtilsEx.isNotBlank(listTenantDTO.getTenantCode())) {
            wrapper.eq(SysTenant::getTenantCode, listTenantDTO.getTenantCode());
        }
        if (StringUtilsEx.isNotBlank(listTenantDTO.getAccountPrefix())) {
            wrapper.eq(SysTenant::getAccountPrefix, listTenantDTO.getAccountPrefix());
        }
        if (StringUtilsEx.isNotBlank(listTenantDTO.getTenantType())) {
            wrapper.eq(SysTenant::getTenantType, listTenantDTO.getTenantType());
        }
        Page<SysTenant> page = page(new Page<>(listTenantDTO.getPageNo(), listTenantDTO.getPageSize()), wrapper);
        return CorePageUtil.buildPageResult(page, SysTenantVO.class);
    }

    @Override
    public List<SysTenantVO> dropDownTenants() {
        QueryWrapper<SysTenant> query = Wrappers.query();
        query.select("tenant_id", "tenant_name");
        if (!SecureUtil.isHeadquarters()) {
            query.eq("tenant_id", SecureUtil.userTenantId());
        }
        List<SysTenant> list = this.list(query);
        return list.stream().map(e -> {
            SysTenantVO sysTenantVO = new SysTenantVO();
            sysTenantVO.setTenantId(e.getTenantId());
            sysTenantVO.setTenantName(e.getTenantName());
            return sysTenantVO;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean configTenantPer(SysTenantDTO tenantDTO) {
        QueryWrapper<SysRole> queryRole = Wrappers.query();
        queryRole.select("role_id", "role_code");
        queryRole.eq("tenant_id", tenantDTO.getTenantId());
        List<SysRole> tenantAllRole = sysRoleService.list(queryRole);
        SysRole tenantAdminRole = tenantAllRole.stream().filter(
                e -> TenantConstant.TENANT_ADMINISTRATOR.equals(e.getRoleCode())).findFirst().get();
        // 查询租户之前所拥有的所有权限
        List<SysRoleMenu> oldPres = sysRoleMenuService.list(Wrappers.<SysRoleMenu>lambdaQuery().eq(SysRoleMenu::getRoleId, tenantAdminRole.getRoleId()));
        // [1,2]
        List<Long> oldMenuIds = oldPres.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());
        // [3,4,5]
        List<Long> newMenuIds = Arrays.stream(tenantDTO.getMenuIds().split(",")).mapToLong(Long::parseLong).boxed().collect(Collectors.toList());
        // 找出被删除的权限ID
        List<Long> diffMenus = oldMenuIds.stream().filter(e -> !newMenuIds.contains(e)).collect(Collectors.toList());
        if (!CollectionUtil.isEmpty(diffMenus)) {
            List<Long> allRoleId = tenantAllRole.stream().map(SysRole::getRoleId).collect(Collectors.toList());
            sysRoleMenuService.remove(Wrappers.<SysRoleMenu>lambdaQuery().in(SysRoleMenu::getMenuId, diffMenus).in(SysRoleMenu::getRoleId, allRoleId));
        }
        sysRoleService.saveRoleMenu(tenantDTO.getMenuIds(), tenantAdminRole.getRoleId());
        return true;
    }

    @Override
    public boolean changeTenantStatus(Long tenantId, Integer tenantStatus) {
        LambdaUpdateWrapper<SysTenant> updateWrapper = Wrappers.<SysTenant>lambdaUpdate()
                .set(SysTenant::getTenantStatus, tenantStatus)
                .eq(SysTenant::getTenantId, tenantId)
                .notIn(SysTenant::getTenantCode, TenantConstant.EC_HEADQUARTERS);
        return this.update(updateWrapper);
    }

    private InitTenantAccountVO initAccount(SysTenant sysTenant, Long deptId, Long roleId) {
        InitTenantAccountVO initTenantAccountVO = new InitTenantAccountVO();
        SysUser sysUser = new SysUser();
        sysUser.setTenantId(sysTenant.getTenantId());
        sysUser.setDeptId(deptId);
        sysUser.setUserMobile(sysTenant.getContactNumber());
        sysUser.setUserName(sysTenant.getContacts());
        sysUser.setUserRealName(sysTenant.getContacts());
        sysUser.setSysData(CommonConstant.SYS_DATA);
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String initPassword = CoreRandomUtil.random(6, RandomTypeEnum.ALL);
        String encodePwd = CoreMd5Util.md5Encrypt(initPassword).toLowerCase();
        sysUser.setUserPassword(bCryptPasswordEncoder.encode(encodePwd));

        int count = sysUserService.userCount(sysTenant.getTenantId());
        //租户支持2～4位
        sysUser.setUserAccount(CoreGenerateIdUtil.userAccount(sysTenant.getAccountPrefix(), 8 - sysTenant.getAccountPrefix().length(), count + 1));
        sysUserService.save(sysUser);
        // 用户角色关联关系
        SysRoleUser SysRoleUser = new SysRoleUser();
        SysRoleUser.setUserId(sysUser.getUserId());
        SysRoleUser.setRoleId(roleId);
        sysRoleUserService.save(SysRoleUser);
        // 返回给应用层信息
        initTenantAccountVO.setUserAccount(sysUser.getUserAccount());
        initTenantAccountVO.setUserName(sysUser.getUserName());
        initTenantAccountVO.setUserPassword(initPassword);
        return initTenantAccountVO;
    }
}
